from typing import Dict, Any, List
import json
import aiohttp
from datetime import datetime
from .base import BaseCollector
from ..models.bond import Session, ConvertibleBond
from ..utils.logger import get_logger
from ..utils.config import config

logger = get_logger(__name__)

class EastMoneyCollector(BaseCollector):
    """东方财富网可转债爬虫"""

    def __init__(self):
        super().__init__()
        self.api_url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
        self.params = {
            "sortColumns": "PUBLIC_START_DATE",
            "sortTypes": "-1",
            "pageSize": "500",
            "pageNumber": "1",
            "reportName": "RPT_BOND_CB_LIST",
            "columns": "ALL",
            "source": "WEB",
            "client": "WEB"
        }
        self.headers = {
            "User-Agent": config.get('crawler.eastmoney.headers.User-Agent'),
            "Referer": "https://data.eastmoney.com/",
            "Accept": "application/json"
        }

    async def collect(self) -> None:
        """收集数据"""
        try:
            async with aiohttp.ClientSession(headers=self.headers) as session:
                async with session.get(self.api_url, params=self.params) as response:
                    if response.status == 200:
                        content = await response.text()
                        data = await self.parse(content)
                        await self.save(data)
                    else:
                        logger.error(f"Failed to collect data from East Money, status: {response.status}")
        except Exception as e:
            logger.error(f"Error in collecting data: {e}")

    async def parse(self, content: str) -> Dict[str, List[Dict[str, Any]]]:
        """解析数据"""
        bonds = []
        try:
            data = json.loads(content)
            if data.get('result') and data['result'].get('data'):
                for item in data['result']['data']:
                    bond = {
                        'bond_code': item.get('SECURITY_CODE', ''),
                        'bond_name': item.get('SECURITY_NAME_ABBR', ''),
                        'stock_code': item.get('CONVERT_STOCK_CODE', ''),
                        'stock_name': item.get('CONVERT_STOCK_NAME', ''),
                        'issue_date': self._parse_date(item.get('VALUE_DATE', '')),
                        'apply_date': self._parse_date(item.get('PUBLIC_START_DATE', '')),
                        'listing_date': self._parse_date(item.get('LISTING_DATE', '')),
                        'delisting_date': self._parse_date(item.get('DELIST_DATE', '')),
                        'issue_price': self._parse_float(item.get('ISSUE_PRICE', '')),
                        'issue_size': self._parse_float(item.get('ACTUAL_ISSUE_SCALE', '')),
                        'convert_price': self._parse_float(item.get('CONVERT_PRICE', '')),
                        'convert_value': self._parse_float(item.get('CONVERT_VALUE', '')),
                        'premium_rate': self._parse_float(item.get('PREMIUM_RATIO', '')),
                        'rating': item.get('RATING', ''),
                        'guarantee': item.get('GUARANTEE_TYPE', '')
                    }
                    bonds.append(bond)
                logger.info(f"Successfully parsed {len(bonds)} bonds")
            else:
                logger.warning("No data found in response")

        except Exception as e:
            logger.error(f"Error in parsing data: {e}")

        return {'bonds': bonds}

    async def save(self, data: Dict[str, List[Dict[str, Any]]]) -> None:
        """保存数据"""
        session = Session()
        try:
            for bond_data in data['bonds']:
                # 检查是否已存在
                existing_bond = session.query(ConvertibleBond).filter_by(
                    bond_code=bond_data['bond_code']
                ).first()

                if existing_bond:
                    # 更新现有记录
                    for key, value in bond_data.items():
                        setattr(existing_bond, key, value)
                else:
                    # 创建新记录
                    new_bond = ConvertibleBond(**bond_data)
                    session.add(new_bond)

            session.commit()
            logger.info(f"Successfully saved {len(data['bonds'])} bonds")

        except Exception as e:
            session.rollback()
            logger.error(f"Error in saving data: {e}")
        finally:
            session.close()

    @staticmethod
    def _parse_date(date_str: str) -> datetime.date:
        """解析日期字符串"""
        if not date_str:
            return None
        try:
            return datetime.strptime(date_str[:10], '%Y-%m-%d').date()
        except:
            return None

    @staticmethod
    def _parse_float(value: Any) -> float:
        """解析浮点数"""
        if value is None or value == '':
            return None
        try:
            return float(str(value).replace(',', ''))
        except:
            return None 